bitkeeper revision 1.1159.201.1 (41ab6fa1bs5vtddKGV1tNJawdZEZdw)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Mon, 29 Nov 2004 18:51:13 +0000 (18:51 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Mon, 29 Nov 2004 18:51:13 +0000 (18:51 +0000)
New /dev/mem patch moves the Xen specifics out to an arch-specific
file. Read/writes of /dev/mem now access I/O space rather than kernel
space. Fixed ioremap.c a whole lot to now use the rather more robust
direct_remap_area_pages(). 'dmidecode' now works in DOM0. :-)

.rootkeys
linux-2.6.9-xen-sparse/arch/xen/i386/mm/ioremap.c
linux-2.6.9-xen-sparse/arch/xen/kernel/Makefile
linux-2.6.9-xen-sparse/arch/xen/kernel/devmem.c [new file with mode: 0644]
linux-2.6.9-xen-sparse/drivers/char/mem.c
linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/io.h

index 8bda240f8f4ba009628a6a35d933f45e6c53d935..1691f867c4f7633ad5a399317f30408d0df2a687 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 4107adf1s5u6249DNPUViX1YNagbUQ linux-2.6.9-xen-sparse/arch/xen/i386/pci/irq.c
 40f56239zOksGg_H4XD4ye6iZNtoZA linux-2.6.9-xen-sparse/arch/xen/kernel/Makefile
 40f56239bvOjuuuViZ0XMlNiREFC0A linux-2.6.9-xen-sparse/arch/xen/kernel/ctrl_if.c
+41ab6fa06JdF7jxUsuDcjN3UhuIAxg linux-2.6.9-xen-sparse/arch/xen/kernel/devmem.c
 40f56238xFQe9T7M_U_FItM-bZIpLw linux-2.6.9-xen-sparse/arch/xen/kernel/evtchn.c
 4110f478aeQWllIN7J4kouAHiAqrPw linux-2.6.9-xen-sparse/arch/xen/kernel/fixup.c
 412dfae9eA3_6e6bCGUtg1mj8b56fQ linux-2.6.9-xen-sparse/arch/xen/kernel/gnttab.c
index f97d3f6b4d6515d21fa7e45c8d45a1b98719f1fe..d28a636c77f287be21ddbe732574aaff74d1c555 100644 (file)
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 #include <asm/pgtable.h>
+#include <asm/pgalloc.h>
 
 #ifndef CONFIG_XEN_PHYSDEV_ACCESS
 
-void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
-{ return NULL; }
+void * __ioremap(unsigned long phys_addr, unsigned long size,
+               unsigned long flags)
+{
+       return NULL;
+}
 
 void *ioremap_nocache (unsigned long phys_addr, unsigned long size)
-{ return NULL; }
+{
+       return NULL;
+}
 
 void iounmap(volatile void __iomem *addr)
-{ }
+{
+}
 
 void __init *bt_ioremap(unsigned long phys_addr, unsigned long size)
-{ return NULL; }
+{
+       return NULL;
+}
 
 void __init bt_iounmap(void *addr, unsigned long size)
-{ }
+{
+}
 
 #else
 
@@ -50,86 +60,6 @@ static inline int is_local_lowmem(unsigned long address)
        return ((pfn < max_low_pfn) && (pfn_to_mfn(pfn) == mfn));
 }
 
-static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
-       unsigned long phys_addr, unsigned long flags)
-{
-       unsigned long end;
-       unsigned long pfn;
-
-       address &= ~PMD_MASK;
-       end = address + size;
-       if (end > PMD_SIZE)
-               end = PMD_SIZE;
-       if (address >= end)
-               BUG();
-       pfn = phys_addr >> PAGE_SHIFT;
-       do {
-               if (!pte_none(*pte)) {
-                       printk("remap_area_pte: page already exists\n");
-                       BUG();
-               }
-               set_pte(pte, pfn_pte_ma(pfn, __pgprot(_PAGE_PRESENT | _PAGE_RW | 
-                                       _PAGE_DIRTY | _PAGE_ACCESSED | flags)));
-               address += PAGE_SIZE;
-               pfn++;
-               pte++;
-       } while (address && (address < end));
-}
-
-static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
-       unsigned long phys_addr, unsigned long flags)
-{
-       unsigned long end;
-
-       address &= ~PGDIR_MASK;
-       end = address + size;
-       if (end > PGDIR_SIZE)
-               end = PGDIR_SIZE;
-       phys_addr -= address;
-       if (address >= end)
-               BUG();
-       do {
-               pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address);
-               if (!pte)
-                       return -ENOMEM;
-               remap_area_pte(pte, address, end - address, address + phys_addr, flags);
-               address = (address + PMD_SIZE) & PMD_MASK;
-               pmd++;
-       } while (address && (address < end));
-       return 0;
-}
-
-static int remap_area_pages(unsigned long address, unsigned long phys_addr,
-                                unsigned long size, unsigned long flags)
-{
-       int error;
-       pgd_t * dir;
-       unsigned long end = address + size;
-
-       phys_addr -= address;
-       dir = pgd_offset(&init_mm, address);
-       flush_cache_all();
-       if (address >= end)
-               BUG();
-       spin_lock(&init_mm.page_table_lock);
-       do {
-               pmd_t *pmd;
-               pmd = pmd_alloc(&init_mm, dir, address);
-               error = -ENOMEM;
-               if (!pmd)
-                       break;
-               if (remap_area_pmd(pmd, address, end - address,
-                                        phys_addr + address, flags))
-                       break;
-               error = 0;
-               address = (address + PGDIR_SIZE) & PGDIR_MASK;
-               dir++;
-       } while (address && (address < end));
-       spin_unlock(&init_mm.page_table_lock);
-       flush_tlb_all();
-       return error;
-}
-
 /*
  * Generic mapping function (not visible outside):
  */
@@ -192,7 +122,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l
                return NULL;
        area->phys_addr = phys_addr;
        addr = (void __iomem *) area->addr;
-       if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
+       if (direct_remap_area_pages(&init_mm, (unsigned long) addr, phys_addr, size, __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | flags), DOMID_IO)) {
                vunmap((void __force *) addr);
                return NULL;
        }
@@ -360,138 +290,145 @@ void __init bt_iounmap(void *addr, unsigned long size)
 #define direct_mk_pte_phys(physpage, pgprot) \
   __direct_mk_pte((physpage) >> PAGE_SHIFT, pgprot)
 
-static inline void direct_remap_area_pte(pte_t *pte, 
-                                        unsigned long address, 
-                                        unsigned long size,
-                                       mmu_update_t **v)
+static inline void direct_remap_area_pte(
+       pte_t *pte, 
+       unsigned long address, 
+       unsigned long size,
+       mmu_update_t **v)
 {
-    unsigned long end;
-
-    address &= ~PMD_MASK;
-    end = address + size;
-    if (end > PMD_SIZE)
-        end = PMD_SIZE;
-    if (address >= end)
-        BUG();
-
-    do {
-        (*v)->ptr = virt_to_machine(pte);
-        (*v)++;
-        address += PAGE_SIZE;
-        pte++;
-    } while (address && (address < end));
+       unsigned long end;
+
+       address &= ~PMD_MASK;
+       end = address + size;
+       if (end > PMD_SIZE)
+               end = PMD_SIZE;
+       if (address >= end)
+               BUG();
+
+       do {
+               (*v)->ptr = virt_to_machine(pte);
+               (*v)++;
+               address += PAGE_SIZE;
+               pte++;
+       } while (address && (address < end));
 }
 
-static inline int direct_remap_area_pmd(struct mm_struct *mm,
-                                        pmd_t *pmd, 
-                                        unsigned long address, 
-                                        unsigned long size,
-                                       mmu_update_t **v)
+static inline int direct_remap_area_pmd(
+       struct mm_struct *mm,
+       pmd_t *pmd, 
+       unsigned long address, 
+       unsigned long size,
+       mmu_update_t **v)
 {
-    unsigned long end;
-
-    address &= ~PGDIR_MASK;
-    end = address + size;
-    if (end > PGDIR_SIZE)
-        end = PGDIR_SIZE;
-    if (address >= end)
-        BUG();
-    do {
-        pte_t *pte = pte_alloc_map(mm, pmd, address);
-        if (!pte)
-            return -ENOMEM;
-        direct_remap_area_pte(pte, address, end - address, v);
-       pte_unmap(pte);
-        address = (address + PMD_SIZE) & PMD_MASK;
-        pmd++;
-    } while (address && (address < end));
-    return 0;
+       unsigned long end;
+
+       address &= ~PGDIR_MASK;
+       end = address + size;
+       if (end > PGDIR_SIZE)
+               end = PGDIR_SIZE;
+       if (address >= end)
+               BUG();
+       do {
+               pte_t *pte = (mm == &init_mm) ? 
+                       pte_alloc_kernel(mm, pmd, address) :
+                       pte_alloc_map(mm, pmd, address);
+               if (!pte)
+                       return -ENOMEM;
+               direct_remap_area_pte(pte, address, end - address, v);
+               pte_unmap(pte);
+               address = (address + PMD_SIZE) & PMD_MASK;
+               pmd++;
+       } while (address && (address < end));
+       return 0;
 }
  
-int __direct_remap_area_pages(struct mm_struct *mm,
-                             unsigned long address, 
-                             unsigned long size, 
-                             mmu_update_t *v)
+int __direct_remap_area_pages(
+       struct mm_struct *mm,
+       unsigned long address, 
+       unsigned long size, 
+       mmu_update_t *v)
 {
-    pgd_t * dir;
-    unsigned long end = address + size;
-
-    dir = pgd_offset(mm, address);
-    flush_cache_all();
-    if (address >= end)
-        BUG();
-    spin_lock(&mm->page_table_lock);
-    do {
-        pmd_t *pmd = pmd_alloc(mm, dir, address);
-        if (!pmd)
-           return -ENOMEM;
-        direct_remap_area_pmd(mm, pmd, address, end - address, &v);
-        address = (address + PGDIR_SIZE) & PGDIR_MASK;
-        dir++;
-
-    } while (address && (address < end));
-    spin_unlock(&mm->page_table_lock);
-    flush_tlb_all();
-    return 0;
+       pgd_t * dir;
+       unsigned long end = address + size;
+
+       dir = pgd_offset(mm, address);
+       if (address >= end)
+               BUG();
+       spin_lock(&mm->page_table_lock);
+       do {
+               pmd_t *pmd = pmd_alloc(mm, dir, address);
+               if (!pmd)
+                       return -ENOMEM;
+               direct_remap_area_pmd(mm, pmd, address, end - address, &v);
+               address = (address + PGDIR_SIZE) & PGDIR_MASK;
+               dir++;
+
+       } while (address && (address < end));
+       spin_unlock(&mm->page_table_lock);
+       return 0;
 }
 
 
-int direct_remap_area_pages(struct mm_struct *mm,
-                            unsigned long address, 
-                            unsigned long machine_addr,
-                            unsigned long size, 
-                            pgprot_t prot,
-                            domid_t  domid)
+int direct_remap_area_pages(
+       struct mm_struct *mm,
+       unsigned long address, 
+       unsigned long machine_addr,
+       unsigned long size, 
+       pgprot_t prot,
+       domid_t  domid)
 {
-    int i;
-    unsigned long start_address;
+       int i;
+       unsigned long start_address;
 #define MAX_DIRECTMAP_MMU_QUEUE 130
-    mmu_update_t u[MAX_DIRECTMAP_MMU_QUEUE], *w, *v;
-
-    u[0].ptr  = MMU_EXTENDED_COMMAND;
-    u[0].val  = MMUEXT_SET_FOREIGNDOM;
-    u[0].val |= (unsigned long)domid << 16;
-    v = w = &u[1];
-
-    start_address = address;
-
-    for( i = 0; i < size; i += PAGE_SIZE )
-    {
-       if ( (v - u) == MAX_DIRECTMAP_MMU_QUEUE )
-       {
-           /* Fill in the PTE pointers. */
-           __direct_remap_area_pages( mm,
-                                      start_address, 
-                                      address-start_address, 
-                                      w);
-           
-           if ( HYPERVISOR_mmu_update(u, v - u, NULL) < 0 )
-               return -EFAULT;     
-           v = w;
-           start_address = address;
+       mmu_update_t u[MAX_DIRECTMAP_MMU_QUEUE], *w, *v;
+
+       u[0].ptr  = MMU_EXTENDED_COMMAND;
+       u[0].val  = MMUEXT_SET_FOREIGNDOM;
+       u[0].val |= (unsigned long)domid << 16;
+       v = w = &u[1];
+
+       start_address = address;
+
+       flush_cache_all();
+
+       for (i = 0; i < size; i += PAGE_SIZE) {
+               if ((v - u) == MAX_DIRECTMAP_MMU_QUEUE) {
+                       /* Fill in the PTE pointers. */
+                       __direct_remap_area_pages(
+                               mm,
+                               start_address, 
+                               address-start_address, 
+                               w);
+       
+                       if (HYPERVISOR_mmu_update(u, v - u, NULL) < 0)
+                               return -EFAULT;
+                       v = w;
+                       start_address = address;
+               }
+
+               /*
+                * Fill in the machine address: PTE ptr is done later by
+                * __direct_remap_area_pages(). 
+                */
+               v->val = (machine_addr & PAGE_MASK) | pgprot_val(prot);
+
+               machine_addr += PAGE_SIZE;
+               address += PAGE_SIZE; 
+               v++;
        }
 
-       /*
-         * Fill in the machine address: PTE ptr is done later by
-         * __direct_remap_area_pages(). 
-         */
-        v->val = (machine_addr & PAGE_MASK) | pgprot_val(prot);
-
-        machine_addr += PAGE_SIZE;
-        address += PAGE_SIZE; 
-        v++;
-    }
-
-    if ( v != w )
-    {
-       /* get the ptep's filled in */
-       __direct_remap_area_pages(mm,
-                                  start_address, 
-                                  address-start_address, 
-                                  w);   
-       if ( unlikely(HYPERVISOR_mmu_update(u, v - u, NULL) < 0) )
-           return -EFAULT;         
-    }
-    
-    return 0;
+       if (v != w) {
+               /* get the ptep's filled in */
+               __direct_remap_area_pages(
+                       mm,
+                       start_address, 
+                       address-start_address, 
+                       w);
+               if (unlikely(HYPERVISOR_mmu_update(u, v - u, NULL) < 0))
+                       return -EFAULT; 
+       }
+
+       flush_tlb_all();
+
+       return 0;
 }
index 3e987bee23d2cf2bcca026047a8a26caf170b147..26731eff3130d751c2181d177c40b14ead76575e 100644 (file)
@@ -9,4 +9,4 @@ $(obj)/vmlinux.lds:
 
 extra-y += vmlinux.lds
 
-obj-y  := ctrl_if.o evtchn.o fixup.o reboot.o xen_proc.o gnttab.o skbuff.o
+obj-y  := ctrl_if.o evtchn.o fixup.o reboot.o xen_proc.o gnttab.o skbuff.o devmem.o
diff --git a/linux-2.6.9-xen-sparse/arch/xen/kernel/devmem.c b/linux-2.6.9-xen-sparse/arch/xen/kernel/devmem.c
new file mode 100644 (file)
index 0000000..ffda098
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ *  Originally from linux/drivers/char/mem.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Added devfs support. 
+ *    Jan-11-1998, C. Scott Ananian <cananian@alumni.princeton.edu>
+ *  Shared /dev/zero mmaping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com>
+ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/mman.h>
+#include <linux/random.h>
+#include <linux/init.h>
+#include <linux/raw.h>
+#include <linux/tty.h>
+#include <linux/capability.h>
+#include <linux/smp_lock.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/ptrace.h>
+#include <linux/device.h>
+#include <asm/pgalloc.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+static inline int uncached_access(struct file *file, unsigned long addr)
+{
+        if (file->f_flags & O_SYNC)
+                return 1;
+        /* Xen sets correct MTRR type on non-RAM for us. */
+        return 0;
+}
+
+/*
+ * This funcion reads the *physical* memory. The f_pos points directly to the 
+ * memory location. 
+ */
+static ssize_t read_mem(struct file * file, char __user * buf,
+                       size_t count, loff_t *ppos)
+{
+       unsigned long i, p = *ppos;
+       ssize_t read = 0;
+       void *v;
+
+       if ((v = ioremap(p, count)) == NULL) {
+               /*
+                * Some programs (e.g., dmidecode) groove off into weird RAM
+                * areas where no table scan possibly exist (because Xen will
+                * have stomped on them!). These programs get rather upset if
+                 * we let them know that Xen failed their access, so we fake
+                 * out a read of all zeroes. :-)
+                */
+               for (i = 0; i < count; i++)
+                       if (put_user(0, buf+i))
+                               return -EFAULT;
+               return count;
+       }
+       if (copy_to_user(buf, v, count))
+               return -EFAULT;
+       iounmap(v);
+
+       read += count;
+       *ppos += read;
+
+       return read;
+}
+
+static ssize_t write_mem(struct file * file, const char __user * buf, 
+                        size_t count, loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       ssize_t written = 0;
+       void *v;
+
+       if ((v = ioremap(p, count)) == NULL)
+               return -EFAULT;
+       if (copy_to_user(v, buf, count))
+               return -EFAULT;
+       iounmap(v);
+
+       written += count;
+       *ppos += written;
+
+       return written;
+}
+
+static int mmap_mem(struct file * file, struct vm_area_struct * vma)
+{
+       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       int uncached;
+
+       uncached = uncached_access(file, offset);
+       if (uncached)
+               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+       /* Don't try to swap out physical pages.. */
+       vma->vm_flags |= VM_RESERVED;
+
+       /*
+        * Don't dump addresses that are not real memory to a core file.
+        */
+       if (uncached)
+               vma->vm_flags |= VM_IO;
+
+       if (io_remap_page_range(vma, vma->vm_start, offset, 
+                               vma->vm_end-vma->vm_start, vma->vm_page_prot))
+               return -EAGAIN;
+
+       return 0;
+}
+
+/*
+ * The memory devices use the full 32/64 bits of the offset, and so we cannot
+ * check against negative addresses: they are ok. The return value is weird,
+ * though, in that case (0).
+ *
+ * also note that seeking relative to the "end of file" isn't supported:
+ * it has no meaning, so it returns -EINVAL.
+ */
+static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
+{
+       loff_t ret;
+
+       down(&file->f_dentry->d_inode->i_sem);
+       switch (orig) {
+               case 0:
+                       file->f_pos = offset;
+                       ret = file->f_pos;
+                       force_successful_syscall_return();
+                       break;
+               case 1:
+                       file->f_pos += offset;
+                       ret = file->f_pos;
+                       force_successful_syscall_return();
+                       break;
+               default:
+                       ret = -EINVAL;
+       }
+       up(&file->f_dentry->d_inode->i_sem);
+       return ret;
+}
+
+static int open_mem(struct inode * inode, struct file * filp)
+{
+       return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
+}
+
+struct file_operations mem_fops = {
+       .llseek         = memory_lseek,
+       .read           = read_mem,
+       .write          = write_mem,
+       .mmap           = mmap_mem,
+       .open           = open_mem,
+};
index 072c5ca76145265d33512c085f6bd85085562359..c805a2ca48f9013f1d546a2fb489e91742f5544a 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/pgalloc.h>
 
 #ifdef CONFIG_IA64
 # include <linux/efi.h>
@@ -43,12 +42,7 @@ extern void tapechar_init(void);
  */
 static inline int uncached_access(struct file *file, unsigned long addr)
 {
-#ifdef CONFIG_XEN
-        if (file->f_flags & O_SYNC)
-                return 1;
-        /* Xen sets correct MTRR type on non-RAM for us. */
-        return 0;
-#elif defined(__i386__)
+#if defined(__i386__)
        /*
         * On the PPro and successors, the MTRRs are used to set
         * memory types for physical addresses outside main memory,
@@ -149,7 +143,7 @@ static ssize_t do_write_mem(void *p, unsigned long realp,
        return written;
 }
 
-
+#ifndef ARCH_HAS_DEV_MEM
 /*
  * This funcion reads the *physical* memory. The f_pos points directly to the 
  * memory location. 
@@ -195,8 +189,9 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
                return -EFAULT;
        return do_write_mem(__va(p), p, buf, count, ppos);
 }
+#endif
 
-static int mmap_mem(struct file * file, struct vm_area_struct * vma)
+static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
 {
        unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
        int uncached;
@@ -216,15 +211,9 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma)
        if (uncached)
                vma->vm_flags |= VM_IO;
 
-#if defined(CONFIG_XEN)
-       if (io_remap_page_range(vma, vma->vm_start, offset, 
-                               vma->vm_end-vma->vm_start, vma->vm_page_prot))
-               return -EAGAIN;
-#else
        if (remap_page_range(vma, vma->vm_start, offset, vma->vm_end-vma->vm_start,
                             vma->vm_page_prot))
                return -EAGAIN;
-#endif
        return 0;
 }
 
@@ -584,7 +573,7 @@ static int open_port(struct inode * inode, struct file * filp)
        return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
 }
 
-#define mmap_kmem      mmap_mem
+#define mmap_mem       mmap_kmem
 #define zero_lseek     null_lseek
 #define full_lseek      null_lseek
 #define write_zero     write_null
@@ -592,6 +581,7 @@ static int open_port(struct inode * inode, struct file * filp)
 #define open_mem       open_port
 #define open_kmem      open_mem
 
+#ifndef ARCH_HAS_DEV_MEM
 static struct file_operations mem_fops = {
        .llseek         = memory_lseek,
        .read           = read_mem,
@@ -599,6 +589,9 @@ static struct file_operations mem_fops = {
        .mmap           = mmap_mem,
        .open           = open_mem,
 };
+#else
+extern struct file_operations mem_fops;
+#endif
 
 static struct file_operations kmem_fops = {
        .llseek         = memory_lseek,
index 0837c81cfaac7ac23345d452d201823fc3212e3a..08667ae0f65dc6378b8d729e477e7d624a42c6b6 100644 (file)
@@ -444,4 +444,7 @@ BUILDIO(b,b,char)
 BUILDIO(w,w,short)
 BUILDIO(l,,int)
 
+/* We will be supplying our own /dev/mem implementation */
+#define ARCH_HAS_DEV_MEM
+
 #endif